package com.rongji.cms.tools.flowable.service.impl;/**
 * @author yang
 * @date 2022/9/20 13:37
 * @description
 */

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.rongji.cms.tools.common.core.domain.PageQuery;
import com.rongji.cms.tools.common.core.page.TableDataInfo;
import com.rongji.cms.tools.flowable.domain.vo.WfDefinitionVo;
import com.rongji.cms.tools.flowable.enums.FlowComment;
import com.rongji.cms.tools.flowable.factory.FlowServiceFactory;
import com.rongji.cms.tools.flowable.service.IWfDefinitionService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.DeploymentBuilder;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.repository.ProcessDefinitionQuery;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.image.impl.DefaultProcessDiagramGenerator;
import org.flowable.task.api.Task;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * @author yang
 * @date 2022/9/20 13:37
 * @description 流程定义
 */
@RequiredArgsConstructor
@Service
@Slf4j
public class WfDefinitionServiceImpl extends FlowServiceFactory implements IWfDefinitionService {
    private static final String BPMN_FILE_SUFFIX = ".bpmn";


    /**
     * 流程定义列表
     *
     * @param pageQuery 分页参数
     * @return 流程定义分页列表数据
     */
    @Override
    public TableDataInfo<WfDefinitionVo> list(PageQuery pageQuery) {
        Page<WfDefinitionVo> page = new Page<>();
        // 流程定义列表数据查询
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery()
//                .latestVersion()
//                .orderByProcessDefinitionKey().asc();
//                全部版本都取出来
                .orderByProcessDefinitionVersion().desc();
        long pageTotal = processDefinitionQuery.count();
        if (pageTotal <= 0) {
            return TableDataInfo.build();
        }
        int offset = pageQuery.getPageSize() * (pageQuery.getPageNum() - 1);
        List<ProcessDefinition> definitionList = processDefinitionQuery.listPage(offset, pageQuery.getPageSize());

        List<WfDefinitionVo> definitionVoList = new ArrayList<>();
        for (ProcessDefinition processDefinition : definitionList) {
            String deploymentId = processDefinition.getDeploymentId();
            Deployment deployment = repositoryService.createDeploymentQuery().deploymentId(deploymentId).singleResult();
            WfDefinitionVo vo = new WfDefinitionVo();
            vo.setDefinitionId(processDefinition.getId());
            vo.setProcessKey(processDefinition.getKey());
            vo.setProcessName(processDefinition.getName());
            vo.setVersion(processDefinition.getVersion());
            vo.setCategory(processDefinition.getCategory());
            vo.setDeploymentId(processDefinition.getDeploymentId());
            vo.setSuspended(processDefinition.isSuspended());
//            表单相关的先不要
//            WfFormVo formVo = deployFormService.selectDeployFormByDeployId(deploymentId);
//            if (Objects.nonNull(formVo)) {
//                vo.setFormId(formVo.getFormId());
//                vo.setFormName(formVo.getFormName());
//            }
            // 流程定义时间
            vo.setCategory(deployment.getCategory());
            vo.setDeploymentTime(deployment.getDeploymentTime());
            definitionVoList.add(vo);
        }
        page.setRecords(definitionVoList);
        page.setTotal(pageTotal);
        return TableDataInfo.build(page);
    }


    @Override
    public InputStream readImage(String definitionId) {
        //获得图片流
        DefaultProcessDiagramGenerator diagramGenerator = new DefaultProcessDiagramGenerator();
        BpmnModel bpmnModel = repositoryService.getBpmnModel(definitionId);
        //输出为图片
        return diagramGenerator.generateDiagram(
                bpmnModel,
                "png",
                Collections.emptyList(),
                Collections.emptyList(),
                "宋体",
                "宋体",
                "宋体",
                null,
                1.0,
                false);

    }

//    /**
//     * 读取xml
//     *
//     * @param deployId
//     * @return
//     */
//    @Override
//    public InputStream readImage(String deployId) {
//        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deployId).singleResult();
//        //获得图片流
//        DefaultProcessDiagramGenerator diagramGenerator = new DefaultProcessDiagramGenerator();
//        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
//        //输出为图片
//        return diagramGenerator.generateDiagram(
//                bpmnModel,
//                "png",
//                Collections.emptyList(),
//                Collections.emptyList(),
//                "宋体",
//                "宋体",
//                "宋体",
//                null,
//                1.0,
//                false);
//
//    }

    /**
     * 读取xml
     *
     * @param deployId
     * @return
     */
    @Override
    public String readXml(String deployId) throws IOException {
        ProcessDefinition definition = repositoryService.createProcessDefinitionQuery().deploymentId(deployId).singleResult();
        InputStream inputStream = repositoryService.getResourceAsStream(definition.getDeploymentId(), definition.getResourceName());
        String result = IOUtils.toString(inputStream, StandardCharsets.UTF_8.name());
        return result;
    }

    /**
     * @param fileName
     * @param in
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void importFile(String fileName, InputStream in) {
        String processName = fileName + BPMN_FILE_SUFFIX;
        // 创建流程部署
        DeploymentBuilder deploymentBuilder = repositoryService.createDeployment()
                .name(processName)
                .key(fileName)
//                .category(category)
                .addInputStream(processName, in);
        // 部署
        deploymentBuilder.deploy();
    }


    /**
     * 删除流程定义
     *
     * @param deployId 流程部署ID act_ge_bytearray 表中 deployment_id值
     */
    @Override
    public void delete(String deployId) {
        // true 允许级联删除 ,不设置会导致数据库外键关联异常
        repositoryService.deleteDeployment(deployId, true);
    }


    /**
     * 根据流程定义ID启动流程实例
     *
     * @param procDefId 流程定义Id
     * @param variables 流程变量
     * @return
     */
    @Override
    public String startProcessInstanceById(String procDefId, Map<String, Object> variables) {
        try {
            ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(procDefId)
                    .latestVersion().singleResult();
            if (Objects.nonNull(processDefinition) && processDefinition.isSuspended()) {
                log.error("流程已被挂起,请先激活流程");
                return null;
            }
//           variables.put("skip", true);
//           variables.put(ProcessConstants.FLOWABLE_SKIP_EXPRESSION_ENABLED, true);
            // 设置流程发起人Id到流程中
            /// FIXME: 2022/9/23 yang

            String userId = variables.get("INITIATOR").toString();
            identityService.setAuthenticatedUserId(userId);
            ProcessInstance processInstance = runtimeService.startProcessInstanceById(procDefId, variables);
            // 给第一步申请人节点设置任务执行人和意见 todo:第一个节点不设置为申请人节点有点问题？
            Task task = taskService.createTaskQuery().processInstanceId(processInstance.getProcessInstanceId()).singleResult();
            if (Objects.nonNull(task)) {
                taskService.addComment(task.getId(), processInstance.getProcessInstanceId(), FlowComment.NORMAL.getType(), "发起文章审核申请");
//                taskService.addComment(task.getId(), processInstance.getProcessInstanceId(), FlowComment.NORMAL.getType(), sysUser.getNickName() + "发起流程申请");

                //                taskService.setAssignee(task.getId(), sysUser.getUserId().toString());
                taskService.complete(task.getId(), variables);
            }
            log.info(task.getProcessInstanceId() + "-----------------流程启动成功");
            return task.getProcessInstanceId();
        } catch (Exception e) {
            e.printStackTrace();
            log.error("流程启动错误", e);
            return null;
        }
    }


    /**
     * 激活或挂起流程定义
     *
     * @param state    状态
     * @param deployId 流程部署ID
     *                 流程定义为挂起状态，该流程定义将不允许启动新的流程实例，同时该流程定义下的所有的流程实例都将全部挂起暂停执行
     */
    @Override
    public void updateState(Integer state, String deployId) {
        ProcessDefinition procDef = repositoryService.createProcessDefinitionQuery().deploymentId(deployId).singleResult();
        // 激活
        if (state == 1) {
            repositoryService.activateProcessDefinitionById(procDef.getId(), true, null);
        }
        // 挂起
        if (state == 2) {
            repositoryService.suspendProcessDefinitionById(procDef.getId(), true, null);
        }
    }


}
